package com.chs.recoginition.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chs.recoginition.core.config.WebConfig;
import com.chs.recoginition.core.exception.ApplicationException;
import com.chs.recoginition.core.exception.constant.CommonData;
import com.chs.recoginition.core.exception.constant.ExceptionConstant;
import com.chs.recoginition.core.exception.constant.SystemConstant;
import com.chs.recoginition.core.utils.BeanMapper;
import com.chs.recoginition.core.utils.MailUtil;
import com.chs.recoginition.core.utils.UploadUtil;
import com.chs.recoginition.core.utils.idworker.Sid;
import com.chs.recoginition.mapper.UserinfoMapper;
import com.chs.recoginition.pojo.UserEmailCodeResult;
import com.chs.recoginition.pojo.Userinfo;
import com.chs.recoginition.pojo.WebSocketMessageResult;
import com.chs.recoginition.repository.UserEmailCodeRepository;
import com.chs.recoginition.repository.WebSocketMessageRepository;
import com.chs.recoginition.service.IUserinfoService;
import com.chs.recoginition.vo.JwtResource;
import com.chs.recoginition.vo.PageRespVo;
import com.chs.recoginition.vo.auth.LoginVo;
import com.chs.recoginition.vo.auth.PasswordResetVo;
import com.chs.recoginition.vo.auth.UserPasswordUpdateVo;
import com.chs.recoginition.vo.reqvo.UserPasswordByCodeReqVo;
import com.chs.recoginition.vo.reqvo.UserRegReqVo;
import com.chs.recoginition.vo.reqvo.UserReqVo;
import com.chs.recoginition.vo.reqvo.UserinfoReqVo;
import com.chs.recoginition.vo.respVo.UserInfoRespVo;
import com.chs.recoginition.vo.respVo.UserRespVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 * seckill
 * @author CHS
 * @since 2022-07-23
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UserinfoServiceImpl extends ServiceImpl<UserinfoMapper, Userinfo> implements IUserinfoService {
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private JwtResource jwtResource;
    @Resource
    private WebSocketMessageRepository webSocketMessageRepository;
    @Resource
    private UserEmailCodeRepository userEmailCodeRepository;
    @Resource
    private MailUtil mailUtil;

    @Resource
    private WebConfig webConfig;
    @Autowired
    private Sid sid;

    @Override
    public UserRespVo login(LoginVo loginVo) {

        // 登录
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(
                loginVo.getUsername(),
                loginVo.getPassword());
        Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        UserRespVo user = this.getUserByUsername(loginVo.getUsername());
        Map<String, Object> data = new HashMap<>();
        data.put(webConfig.getJwtUsernameKey(), user.getUsername());
        data.put(webConfig.getJwtNameKey(), user.getNickname());
        user.setToken(jwtResource.generateToken(data));
        return user;
    }

    @Override
    public PageRespVo<UserInfoRespVo> getAllPage(UserinfoReqVo reqVo) {
        return baseMapper.getALLPage(reqVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveInfo(Userinfo info, UserRespVo user) {
        QueryWrapper<Userinfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",info.getUsername()).last("limit 1");
        Userinfo userinfo = baseMapper.selectOne(queryWrapper);

        if(userinfo != null) {
            throw new ApplicationException(ExceptionConstant.ACCOUNT_NUMBER_ALREADY_EXISTS);
        }
        if(StringUtils.isBlank(info.getNickname())) {
            info.setNickname("匿名用户");
        }
        if(StringUtils.isNotBlank(info.getPassword())) {
            info.setPassword(passwordEncoder.encode(info.getPassword()));
        }
        info.setCreatedBy(user.getUserId());
        info.setCreatedTime(LocalDateTime.now());
        return baseMapper.insert(info);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer modify(Userinfo info ,UserRespVo user) {
        if(StringUtils.isNotBlank(info.getPassword())) {
            info.setPassword(passwordEncoder.encode(info.getPassword()));
        }
        info.setUpdatedBy(user.getUserId());
        info.setUpdatedTime(LocalDateTime.now());
        return baseMapper.updateById(info);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer remove(String idList) {
        List<Integer> idLists = Arrays.stream(idList.split(",")).map(Integer::parseInt).collect(Collectors.toList());
        for(Integer id:idLists) {
            Userinfo userinfo = baseMapper.selectById(id);
            if(userinfo == null) {
                throw new ApplicationException(ExceptionConstant.ENTITY_NOT_EXISTS);
            }
            return baseMapper.deleteById(id);
        }
        return idLists.size();
    }

    @Override
    public UserRespVo getUserByUsername(String username) {
        QueryWrapper<Userinfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username).last("limit 1");
        Userinfo userinfo = baseMapper.selectOne(queryWrapper);
        if(userinfo != null) {
            UserRespVo user = BeanMapper.map(userinfo, UserRespVo.class);
            Map<String, Object> data = new HashMap<>();
            data.put(webConfig.getJwtUsernameKey(), user.getUsername());
            data.put(webConfig.getJwtNameKey(), user.getNickname());
            user.setToken(jwtResource.generateToken(data));
            return user;
        }else {
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserRespVo resetPassword(String username, PasswordResetVo vo) {
        vo.setPassword(passwordEncoder.encode(vo.getPassword()));
        return null;
    }

    @Override
    public String refresh(String oldToken) {
        if (jwtResource.canTokenBeRefreshed(oldToken)) {
            return jwtResource.refreshToken(oldToken);
        }
        throw new ApplicationException(ExceptionConstant.TOKEN_CANNOT_REFRESH);
    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return getUserByUsername(s);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(UserPasswordUpdateVo updateVo) {
        if (!updateVo.getPassword().equals(updateVo.getConfirmPassword())) {
            throw new ApplicationException(SystemConstant.SYS_USER_PASSWPRD_ERRPR, "用户两次输入密码不一致");
        }
        QueryWrapper<Userinfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",updateVo.getUsername()).last("limit 1");
        Userinfo userinfo = baseMapper.selectOne(queryWrapper);
        userinfo.setPassword(passwordEncoder.encode(updateVo.getPassword()));
        baseMapper.updateById(userinfo);
    }

    @Override
    public String uploadUserHeader(HttpServletResponse response, MultipartFile file) throws IOException {
        String s = sid.nextShort();
        String result = UploadUtil.uploadPicture(file,  s, "head");
        return result;
    }

    @Override
    public List<WebSocketMessageResult> getRedisMessageList(String channelNum) {
        Iterable<WebSocketMessageResult> all = webSocketMessageRepository.findAll();
        List<WebSocketMessageResult> decreaseList = BeanMapper.mapList(all,
                WebSocketMessageResult.class, WebSocketMessageResult.class);
        List<WebSocketMessageResult> collect = decreaseList.stream().filter(v -> v.getChannelNum().equals(channelNum)).collect(Collectors.toList()).stream().sorted(Comparator.comparing(WebSocketMessageResult::getSendDateTime)).collect(Collectors.toList());
        return collect;
    }

    @Override
    public String findUserEmail(String userOpenId) {
        UserRespVo userByUsername = this.getUserByUsername(userOpenId);
        String email = userByUsername.getEmail();
        if(StringUtils.isBlank(email)) {
            throw new ApplicationException("10011","邮箱不存在");
        }
        return email;
    }

    @Override
    public void sendEmailCodeByReg(String username, String email) {
        if(StringUtils.isBlank(username)) {
            throw new ApplicationException("10082","用户账号不能为空");
        }
        if(StringUtils.isBlank(email)) {
            throw new ApplicationException("10083","用户邮箱不能为空");
        }
        UserRespVo userByOpenId = this.getUserByUsername(username);
        if(userByOpenId != null) {
            throw new ApplicationException(ExceptionConstant.USER_EXISTS);
        }
        String receiver = email;
        String subject = "【重要】图像识别APP-用户注册账号";
        String code = sid.nextShort().substring(4,10);
        UserEmailCodeResult userEmailCodeResult = new UserEmailCodeResult();
        userEmailCodeResult.setCode(code);
        userEmailCodeResult.setUsername(username);
        userEmailCodeResult.setType("reg");
        userEmailCodeRepository.save(userEmailCodeResult);
        String content = "您的邮箱验证码是："+code+"，您正在通过邮箱注册账号,如非本人操作,请忽略该邮件" +
                "（该验证码5分钟内有效，且这是一封系统邮件，请勿回复）";
        String fromName = "图像识别APP";
        String receiverName = username;
        mailUtil.sendTemplateMail(receiver, subject, content,
                fromName, receiverName);
    }

    @Override
    public void saveUserReg(UserRegReqVo reqVo) {
        String code = reqVo.getCode();
        String userOpenId = reqVo.getUsername();
        String userNickName = reqVo.getNickname();
        String userAvatarUrl = reqVo.getHeadImageUrl();
        String email = reqVo.getEmail();
        String password = reqVo.getPassword();
        String sysCode = "";
        UserRespVo userByOpenId = this.getUserByUsername(userOpenId);
        if(userByOpenId != null) {
            throw new ApplicationException(ExceptionConstant.USER_EXISTS);
        }
        List<UserEmailCodeResult> userCodeList = userEmailCodeRepository.findByTypeAndUsernameOrderByIdDesc("reg",userOpenId);
        if(userCodeList.size() > 0) {
            sysCode = userCodeList.get(0).getCode();
        }
        System.out.println(code.toUpperCase(Locale.getDefault()));
        System.out.println(sysCode.toUpperCase(Locale.getDefault()));
        if(!code.toUpperCase(Locale.getDefault()).equals(sysCode.toUpperCase(Locale.getDefault()))) {
            throw new ApplicationException("10072","验证码错误或已过期！！！");
        }
        Userinfo userinfo = new Userinfo();
        userinfo.setUsername(userOpenId);
        userinfo.setPassword(passwordEncoder.encode(password));
        userinfo.setNickname(userNickName);
        userinfo.setEmail(email);
        userinfo.setHeadImageUrl(userAvatarUrl);
        userinfo.setCreatedTime(LocalDateTime.now());
        baseMapper.insert(userinfo);
    }

    @Override
    public void sendEmailCode(String username) {
        UserRespVo userByUsername = this.getUserByUsername(username);
        if(userByUsername == null) {
            throw new ApplicationException(ExceptionConstant.ENTITY_NOT_EXISTS);
        }

        String receiver = userByUsername.getEmail();
        if(StringUtils.isBlank(receiver)) {
            throw new ApplicationException("10011","邮箱不存在");
        }
        String subject = "【重要】图像识别APP-用户修改密码";
        String code = sid.nextShort().substring(4,10);
        UserEmailCodeResult userEmailCodeResult = new UserEmailCodeResult();
        userEmailCodeResult.setCode(code);
        userEmailCodeResult.setUsername(username);
        userEmailCodeResult.setType("code");
        userEmailCodeRepository.save(userEmailCodeResult);
        String content = "您的邮箱验证码是："+code+"，您正在通过邮箱修改密码,如非本人操作,请忽略该邮件。（该验证码10分钟内有效，且这是一封系统邮件，请勿回复）";
        String fromName = "编程大师手游";
        String receiverName = userByUsername.getNickname();
        mailUtil.sendTemplateMail(receiver, subject, content,
                fromName, receiverName);
    }

    @Override
    public void updatePasswordByEmailCode(UserPasswordByCodeReqVo userPasswordByCodeReqVo) {
        String code = userPasswordByCodeReqVo.getCode();
        String password = userPasswordByCodeReqVo.getPassword();
        String confirmPassword = userPasswordByCodeReqVo.getConfirmPassword();
        String userOpenId = userPasswordByCodeReqVo.getUserOpenId();
        UserRespVo user = this.getUserByUsername(userOpenId);
        if(user == null) {
            throw new ApplicationException(ExceptionConstant.ENTITY_NOT_EXISTS);
        }
        if(!confirmPassword.equals(password)) {
            throw new ApplicationException("10071","两次输入的密码不一致！！！");
        }
        String sysCode = "";
//        Iterable<UserEmailCodeResult> all = userEmailCodeRepository.findAll();
//        List<UserEmailCodeResult> userEmailCodeResults = BeanMapper.mapList(all, UserEmailCodeResult.class, UserEmailCodeResult.class);
//        System.out.println("all: "+userEmailCodeResults);
//        List<UserEmailCodeResult> userCodeList = userEmailCodeResults.stream().filter(v -> v.getType().equals("code") && v.getUserOpenId().equals(userOpenId)).collect(Collectors.toList());
        List<UserEmailCodeResult> userCodeList = userEmailCodeRepository.findByTypeAndUsernameOrderByIdDesc("code",userOpenId);
        if(userCodeList.size() > 0) {
            sysCode = userCodeList.get(0).getCode();
        }
        if(!code.toUpperCase(Locale.getDefault()).equals(sysCode.toUpperCase(Locale.getDefault()))) {
            throw new ApplicationException("10072","验证码错误或已过期！！！");
        }
        Userinfo userinfo = new Userinfo();
        userinfo.setUserId(user.getUserId());
        userinfo.setPassword(passwordEncoder.encode(password));
        baseMapper.updateById(userinfo);
    }
}
